/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package harmonic;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFormat.Encoding;

/**
 *
 * @author Alastair
 */
public class FloatingPointAudioConverter {

   public static final Encoding PCM_FLOAT = new Encoding("PCM_FLOAT");

   public static final void toFloatingPoint(AudioFormat srcFmt,
                byte[] src, int srcOffset,
                float[] dst, int dstOffset, int sampleLen){
       //First deal with the case where the source is null
       assertNotNull(src,"src is null.");
       assertNotNull(dst,"dst is null.");
       assertNotNull(srcFmt,"format is null.");

       if (srcFmt.getSampleSizeInBits() % 8 != 0)
           throw new AssertionError("Only sample sizes that are multiples of 8 are accepted.");

       AudioFormat.Encoding srcEncoding = srcFmt.getEncoding();

       if (srcEncoding == AudioFormat.Encoding.PCM_SIGNED ||
               srcEncoding == AudioFormat.Encoding.PCM_UNSIGNED){

       //Now transform to floating point.
       byteToFloat(src, srcOffset, dst, dstOffset, sampleLen,
               srcFmt.getSampleSizeInBits(),
               srcFmt.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED,
               srcFmt.isBigEndian());
       } else if (srcEncoding == PCM_FLOAT){

       } else{
           throw new AssertionError("Unrecognized format encoding " + srcEncoding.toString());
       }
   }

   public static final void toFixedPoint(AudioFormat f, float[] src, int srcOffset, int srcLen,
                byte[] dst, int dstOffset){

   }

    private static final void byteToFloat(byte[] src, int srcOffset,
            float[] dst, int dstOffset, int sampleLen, int bitsPerSample,
            boolean unsigned, boolean bigEndian) {

        int bytesPerSample = (bitsPerSample + 7) / 8;  // Round up
        float scaler = 1f / (float) (1 << ((bitsPerSample) - 1));

        for (int i = 0; i < sampleLen; i++) {
            int value = 0;
            if (bigEndian) {
                for (int j = 0; j < bytesPerSample; j++) {
                    value = value << 8 | (src[srcOffset + i * bytesPerSample + j] & 0xFF);
                }
            } else {
                for (int j = bytesPerSample - 1; j >= 0; j--) {
                    value = value << 8 | (src[srcOffset + i * bytesPerSample + j] & 0xFF);
                }
            }

            if (unsigned) {
                value -= 1 << (bitsPerSample - 1);
            } else {
                value = value << (32 - bitsPerSample) >> (32 - bitsPerSample); // Sign extension
            }

            dst[dstOffset + i] = value * scaler;
        }
    }

    private static final void assertNotNull(Object v, String errorMsg){
        if (v == null)
            throw new NullPointerException(errorMsg);
    }



}